package com.syl.auth.config;

import com.syl.auth.authentication.SmallAccessDecisionManager;
import com.syl.auth.authorization.SmallAuthenticationTokenProvider;
import com.syl.auth.filter.SmallAuthenticationProcessingFilter;
import com.syl.auth.filter.SmallJwtFilter;
import com.syl.auth.handle.SmallAccessDeniedHandler;
import com.syl.auth.handle.SmallAuthenticationEntryPoint;
import com.syl.auth.handle.SmallAuthenticationFailureHandler;
import com.syl.auth.authentication.SmallSecurityMetadataSource;
import com.syl.auth.handle.SmallAuthenticationSuccessHandler;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;


import javax.annotation.Resource;
import java.util.List;

/**
 * @Author YunLong
 * @Date 2023/4/27 23:40
 * @Description 就这一个类SecurityConfig
 **/
@Configuration
@ConditionalOnClass({SmallAuthenticationTokenProvider.class,
        SmallJwtFilter.class,
        SmallAccessDecisionManager.class,
        SmallSecurityMetadataSource.class,
        SmallAuthenticationSuccessHandler.class,
        SmallAuthenticationFailureHandler.class,
        SmallAuthenticationEntryPoint.class,
        SmallSecurityProperties.class,
        SmallAccessDeniedHandler.class})
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Resource
    SmallAuthenticationTokenProvider smallAuthenticationTokenProvider;
    @Resource
    SmallAccessDecisionManager smallAccessDecisionManager;
    @Resource
    SmallSecurityMetadataSource smallSecurityMetadataSource;
    @Resource
    SmallAuthenticationSuccessHandler authenticationSuccessHandler;
    @Resource
    SmallAuthenticationFailureHandler authenticationFailureHandler;
    @Resource
    SmallAuthenticationEntryPoint smallAuthenticationEntryPoint;
    @Resource
    SmallAccessDeniedHandler smallAccessDeniedHandler;
    @Resource
    SmallSecurityProperties smallSecurityProperties;

    @Override
    public void configure(WebSecurity web) throws Exception {
        // 放行静态资源
        List<String> staticResourceUrls = smallSecurityProperties.getStaticResourceUrls();
        web.ignoring().antMatchers((staticResourceUrls.toArray(new String[0])));
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        // 放行指定接口
        List<String> notLoginUrls = smallSecurityProperties.getNotLoginUrls();

        // 关闭 session
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        // 添加 jwt解析
        http.addFilterBefore(new SmallJwtFilter(), BasicAuthenticationFilter.class);
        // 替换原有认证入口filter
        http.addFilterAt(myAuthenticationProcessingFilter(), UsernamePasswordAuthenticationFilter.class);

        // 动态权限控制
        http.authorizeRequests()
                .antMatchers(notLoginUrls.toArray(new String[0]))
                .permitAll()
                .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
                    @Override
                    public <O extends FilterSecurityInterceptor> O postProcess(O o) {
                        o.setSecurityMetadataSource(smallSecurityMetadataSource);
                        o.setAccessDecisionManager(smallAccessDecisionManager);
                        return o;
                    }
                })
                .anyRequest()
                .authenticated()
                .and()
                .csrf()
                .disable();

        // 认证异常
        http.exceptionHandling().authenticationEntryPoint(smallAuthenticationEntryPoint);
        // 鉴权异常
        http.exceptionHandling().accessDeniedHandler(smallAccessDeniedHandler);
    }

    private SmallAuthenticationProcessingFilter myAuthenticationProcessingFilter() {

        SmallAuthenticationProcessingFilter filter = new SmallAuthenticationProcessingFilter();

        filter.setAuthenticationSuccessHandler(authenticationSuccessHandler);

        filter.setAuthenticationFailureHandler(authenticationFailureHandler);

        filter.setAuthenticationManager(new ProviderManager(smallAuthenticationTokenProvider));
        filter.setFilterProcessesUrl(smallSecurityProperties.getLoginUrl());
        return filter;
    }
}
